package com.sparrow.core.asm;

import java.lang.reflect.Method;

import com.sparrow.constant.COMMON;
import com.sparrow.core.Log;
import com.sparrow.utils.StringUtil;

public class Generator4MethodAccessor {
	final String packgeName = "com.sparrow.core.asm.accessMethod";
	private static Generator4MethodAccessor generator4MethodAccessor = new Generator4MethodAccessor();

	private Generator4MethodAccessor() {
	}

	public static Generator4MethodAccessor getInstance() {
		return generator4MethodAccessor;
	}

	private String getWrapClass(Class<?> basicType) {
		if (basicType == int.class) {
			return Integer.class.getName();
		}
		if (basicType == byte.class) {
			return Byte.class.getName();
		}
		if (basicType == short.class) {
			return Short.class.getName();
		}
		if (basicType == long.class) {
			return Long.class.getName();
		}
		if (basicType == float.class) {
			return Float.class.getName();
		}
		if (basicType == double.class) {
			return Double.class.getName();
		}
		if (basicType == char.class) {
			return Character.class.getName();
		}
		if (basicType == boolean.class) {
			return Boolean.class.getName();
		}
		return basicType.getName();
	}

	public MethodAccessor newMothodAccessor(Class<?> clazz) {

		StringBuffer setJavaSource = new StringBuffer();

		StringBuffer getJavaSource = new StringBuffer();

		String operatorClassName = clazz.getName();
		String operatorObjectName = StringUtil.setFirstByteLowerCase(clazz
				.getSimpleName());

		String methodAccessorClassName = clazz.getSimpleName() + "MethodAccess";

		getJavaSource.append("public Object get(Object o, String methodName){");
		getJavaSource.append(COMMON.ENTER_TEXT);
		getJavaSource.append(String.format("%1$s %2$s=(%3$s)o;",
				operatorClassName, operatorObjectName, operatorClassName));
		setJavaSource
				.append("public void set(Object o, String methodName,Object arg){");
		setJavaSource.append(COMMON.ENTER_TEXT);
		setJavaSource.append(String.format("%1$s %2$s=(%3$s)o;",
				operatorClassName, operatorObjectName, operatorClassName));

		Method[] methods = clazz.getMethods();
		for (Method method : methods) {
			Class<?>[] parameterType = method.getParameterTypes();
			if (method.getName().startsWith("set") && parameterType.length == 1) {
				setJavaSource.append(COMMON.ENTER_TEXT);
				setJavaSource.append(String.format(
						"if(methodName.equals(\"%1$s\")){", method.getName()));
				// operatorObjectName.invoke((M(args[0])));

				setJavaSource.append(String.format("%1$s.%2$s((%3$s)arg);}",
						operatorObjectName, method.getName(),
						this.getWrapClass(parameterType[0])));
				setJavaSource.append(COMMON.ENTER_TEXT);

			} else if (method.getName().startsWith("get")
					&& parameterType.length == 0
					&& !method.getReturnType().equals(void.class)) {
				getJavaSource.append(COMMON.ENTER_TEXT);
				getJavaSource.append(String.format(
						"if(methodName.equals(\"%1$s\")){", method.getName()));

				// operatorObjectName.invoke();
				getJavaSource.append(String.format("return %1$s.%2$s();}",
						operatorObjectName, method.getName()));
				getJavaSource.append(COMMON.ENTER_TEXT);

			}
		}
		setJavaSource.append("}");
		setJavaSource.append(COMMON.ENTER_TEXT);
		getJavaSource.append("return null;");
		getJavaSource.append("}");
		getJavaSource.append(COMMON.ENTER_TEXT);
		String sourceCode = "package " + packgeName + ";" + COMMON.ENTER_TEXT
				+ "import com.sparrow.core.asm.MethodAccessor;"
				+ COMMON.ENTER_TEXT + " public class "
				+ methodAccessorClassName + "  implements MethodAccessor{"
				+ COMMON.ENTER_TEXT + getJavaSource.toString()
				+ setJavaSource.toString() + "}";
		System.out.println(sourceCode);

		try {
			MethodAccessor instance = (MethodAccessor) DynamicEngine
					.getInstance().javaCodeToObject(
							packgeName + "." + methodAccessorClassName,
							sourceCode);

			return instance;
		} catch (Exception e) {
			Log.getInstance().error(e);
		}
		return null;
	}
}
